package com.android.settings.audio.peq.peq.ui;

import static com.android.settings.audio.peq.peq.ui.PeqActivityPresenter.REQUEST_IMAGE;

import android.app.ActionBar;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.Spinner;
import android.widget.Switch;
import android.widget.TextView;

import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsControllerCompat;

import com.android.settings.audio.peq.peq.ui.dialog.CommanDialog;
import com.android.settings.audio.peq.peq.view.VerticalAlignImageSpan;
import com.android.settings.audio.peq.util.DspUtil;
import com.google.gson.reflect.TypeToken;
import com.android.settings.R;

import com.android.settings.audio.peq.peq.filter.FilterManager;
import com.android.settings.audio.peq.peq.filter.FilterType;
import com.android.settings.audio.peq.peq.ui.dialog.SoundEffectPrefabsDialog;
import com.android.settings.audio.peq.peq.view.GroupLinearLayout;
import com.android.settings.audio.peq.peq.view.IndTextView;
import com.android.settings.audio.peq.peq.view.LineView;
import com.android.settings.audio.peq.peq.widget.PeqParamDialog;
import com.android.settings.audio.peq.qr.Constant;
import com.android.settings.audio.peq.qr.QrManager;
import com.android.settings.audio.peq.skin.SkinManager;
import com.android.settings.audio.peq.soundeffect.PeqDataManager;
import com.android.settings.audio.peq.soundeffect.PluginDataManager;
import com.android.settings.audio.peq.soundeffect.SoundEffectConfig;
import com.android.settings.audio.peq.soundeffect.SoundEffectManager;
import com.android.settings.audio.peq.peq.Band;
import com.android.settings.audio.peq.peq.Coeff;
import com.android.settings.audio.peq.peq.FrequencyResponse;
import com.android.settings.audio.peq.peq.view.horizontalscrollview.CenterLockHorizontalScrollviewWithTabBg;
import com.android.settings.audio.peq.tools.MmqStateTools;
import com.android.settings.audio.peq.util.BuildConfig;
import com.android.settings.audio.peq.util.LogPlus;
import com.android.settings.audio.peq.util.NetWorkUtils;
import com.android.settings.audio.peq.util.ShareprefenceTool;
import com.android.settings.audio.peq.util.SmartPlayerApplication;
import com.android.settings.audio.peq.util.ToastTool;
import com.android.settings.audio.peq.xqrcode.XQRCode;
import com.android.settings.audio.peq.xqrcode.util.ImageUtil;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class PEQActivity extends BaseActivity implements IPeq.IPeqView {
    private LineView lineView;
    private SeekBar skF, skQ, skGain, skPreAmp;
    private TextView tvFreq, tvQ, tvGain, tvPreAmp;
    private Spinner filterSpinner;
    private Switch bandSwitchButton;
    private Switch globalSwitchButton;
    private List<Band> bands;

    private static final double LOG10_30 = Math.log10(30 * 100);
    private static final double LOG10_20K = Math.log10(20000 * 100);
    private static final double LOG10_20 = Math.log10(20 * 100);
    private static final double LOG10_2K = Math.log10(2000 * 100);

    private IPeq mPresenter;

    public static final int REQUEST_QR_CODE = 2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //navbarColor = getColorMethods(R.color.skin_background);
        super.onCreate(savedInstanceState);
        int layoutResId = R.layout.peq_activity_peq;
        if (BuildConfig.isNewTheme()) {
            layoutResId = R.layout.peq_activity_peq_newtheme;
        }
        setContentView(layoutResId);
        ActionBar actionBar = getActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);
            actionBar.setHomeButtonEnabled(true);
        }
        setStatusBarStatus();
        init();

        //setStatusBarHeight(findViewById(R.id.vg_top_nav));
    }

    private void setStatusBarStatus() {
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        getWindow().setStatusBarColor(getResources().getColor(R.color.peq_status_bar_background));
        WindowInsetsControllerCompat wic = ViewCompat.getWindowInsetsController(getWindow().getDecorView());
        if (wic != null) {
            // true表示Light Mode，状态栏字体呈黑色，反之呈白色
            boolean isNight = (getApplicationContext().getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_YES) != 0;
            wic.setAppearanceLightStatusBars(!isNight);
        }
    }

    private Band currentSelectedBand;
    private IndTextView currentSelectedBandView;

    private void init() {
        SmartPlayerApplication.initContext(getApplicationContext());
        QrManager.getInstance().init(this);

        this.mPresenter = new PeqActivityPresenter(this, this);
        //findViewById(R.id.imgb_nav_back).setOnClickListener(v -> finish());
        findViewById(R.id.mixer_style).setOnClickListener(v -> mPresenter.onTuningStyleClick());
        findViewById(R.id.import_export_mixer).setOnClickListener(v -> mPresenter.onImportExportClick());
        findViewById(R.id.save_mixer).setOnClickListener(v -> mPresenter.onSaveMixerValueClick());
        globalSwitchButton = findViewById(R.id.peq_enable);
        SkinManager.get().setSwitchDrawable(globalSwitchButton, R.drawable.peq_skin_switch_back_drawable);
        SkinManager.get().changeCustomView(globalSwitchButton, true);

        bandSwitchButton = findViewById(R.id.sb_band);
        SkinManager.get().setSwitchDrawable(bandSwitchButton, R.drawable.peq_skin_switch_back_drawable);
        SkinManager.get().changeCustomView(bandSwitchButton, true);
        bandSwitchButton.setOnCheckedChangeListener((buttonView, isChecked) -> {
            LogPlus.d("###isChecked:" + isChecked + " ,ignoreBandSwitchChanged:" + ignoreBandSwitchChanged);
            if (ignoreBandSwitchChanged) {
                return;
            }
            currentSelectedBand.on = isChecked;
            doUpdate(getPreAmp());
            if (mPresenter != null) mPresenter.setPeqValue(currentSelectedBand, getPreAmp());
            if (mPresenter != null) mPresenter.changeToNone();

            enableViews();
            indTextViews[currentSelectedBand.index].setIndEnable(isChecked);
        });

        LinearLayout llPEQ = findViewById(R.id.ll_peq);

        lineView = new LineView(this);
        lineView.setVisibility(View.VISIBLE);
        llPEQ.addView(lineView.execute2("", ""), new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));

        skF = findViewById(R.id.sk_f);
        skQ = findViewById(R.id.sk_q);
        skGain = findViewById(R.id.sk_gain);
        skPreAmp = findViewById(R.id.sk_pre_amp);
        for (SeekBar sk : new SeekBar[]{skF, skQ, skGain, skPreAmp}) {
            Drawable drawable = getDrawable(getThumbDrawableResId());//共用
            if (skPreAmp == sk) {
                //单独一个drawable
                drawable = new BitmapDrawable(getResources(), BitmapFactory.decodeResource(getResources(), getThumbDrawableResId()));
            }
            sk.setThumb(drawable);
        }

        globalSwitchButton.setOnCheckedChangeListener((buttonView, isChecked) -> {
            boolean isMmqPlaying = MmqStateTools.getInstance().currentMusicIsMMq();
            if (isMmqPlaying) {
                globalSwitchButton.setChecked(false);
                ToastTool.showToast(this, getResources().getString(R.string.mmq_state_try_agin_next));
                return;
            }
            ShareprefenceTool.getInstance().setBooleanSharedPreference(PEQ_ISOPEN, isChecked, this.getApplicationContext());
            mPresenter.setPEQEnable(isChecked, (float) getPreAmp(), isChecked);
            if (isChecked) {
                //重新激活时
                mPresenter.setPeqValues(bands, getPreAmp());
            }
            enableViews();
        });

        initSeekbars();

        tvFreq = findViewById(R.id.tv_freq);
        tvQ = findViewById(R.id.tv_q);
        tvGain = findViewById(R.id.tv_gain);
        tvPreAmp = findViewById(R.id.tv_pre_amp);

        tvFreq.setOnClickListener(v -> showParamValueDialog("Frequency:30~20000", (currentSelectedBand.freq / 100) + "", (value) -> {
            try {
                int iv = Integer.parseInt(value);
                if (iv < 30 || iv > 20000) {
                    ToastTool.showToast(this, "30~20000");
                    return false;
                }
                int minProgress = 0;
                if (isSupportedSetMin()) {
                    minProgress = skF.getMin();
                }
                int maxProgress = skF.getMax();
                int progress = iv * 100;
                skF.setProgress(FrequencyResponse.log10ToProgress(LOG10_30, LOG10_20K, minProgress, maxProgress, progress) - getSkFOffsetValue());
                tvFreq.setText(String.format(getString(R.string.peq_freq), iv));
                currentSelectedBand.freq = progress;
                if (BuildConfig.DEBUG) LogPlus.d("###currentSelectedBand.freq:" + currentSelectedBand.freq);
                if (mPresenter != null) mPresenter.changeToNone();
                return true;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return false;
        }));
        tvQ.setOnClickListener(v -> showParamValueDialog("Q:0.20~20.00", String.format("%.2f", currentSelectedBand.getQ()), (value) -> {
            try {
                double dv = Double.parseDouble(value);
                if (dv < 0.2 || dv > 20) {
                    ToastTool.showToast(this, "0.20~20.00");
                    return false;
                }
                int q = (int) (dv * 100 * 100);
                int minProgress = 0;
                if (isSupportedSetMin()) {
                    minProgress = skQ.getMin();
                }
                currentSelectedBand.q = q;
                skQ.setProgress(FrequencyResponse.log10ToProgress(LOG10_20, LOG10_2K, minProgress, skQ.getMax(), /*currentSelectedBand.q*/q) - getSkQOffsetValue());
                tvQ.setText(String.format(getString(R.string.peq_q), currentSelectedBand.getQ()));
                if (BuildConfig.DEBUG) LogPlus.d("currentSelectedBand.q: " + currentSelectedBand.q);
                if (mPresenter != null) mPresenter.changeToNone();
                return true;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return false;
        }));
        tvGain.setOnClickListener(v -> showParamValueDialog("Gain:-9.00~9.00", String.format("%.2f", currentSelectedBand.getGain()), (value) -> {
            try {
                double dv = Double.parseDouble(value);
                if (dv < -9 || dv > 9) {
                    ToastTool.showToast(this, "-9.00~9.00");
                    return false;
                }
                currentSelectedBand.gain = (int) Math.round(dv * 100 * 100);
                skGain.setProgress(currentSelectedBand.gain - getSkGainOffsetValue());
                tvGain.setText(String.format(getString(R.string.peq_gain), dv));
                if (mPresenter != null) mPresenter.changeToNone();
                return true;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return false;
        }));
        tvPreAmp.setOnClickListener(v -> showParamValueDialog("Pre Amp:-9.00~2.00", String.format("%.2f", getPreAmp()), (value) -> {
            try {
                double d = Double.parseDouble(value);
                if (d < -9 || d > 2) {
                    ToastTool.showToast(this, "-9.00~2.00");
                    return false;
                }
                skPreAmp.setProgress((int) (Math.round(d * 100 * 100)) - getSkPreampOffsetValue());
                if (mPresenter != null) {
                    mPresenter.changeToNone();
                    mPresenter.setPEQEnable(globalSwitchButton.isChecked(), (float) getPreAmp(), globalSwitchButton.isChecked());
                }
                return true;
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return false;
        }));

        EditText etFreq = findViewById(R.id.et_freq);
        EditText etQ = findViewById(R.id.et_q);
        EditText etGain = findViewById(R.id.et_gain);
        EditText etPreAmp = findViewById(R.id.et_pre_amp);

        for (View v : new View[]{etFreq, etQ, etGain, etPreAmp}) {
            v.setVisibility(View.GONE);
        }

        skF.setOnSeekBarChangeListener(new SimpleOnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                if (ignoreSkFChanged) {
                    return;
                }
                double minProgress = 0;
                if (isSupportedSetMin()) {
                    minProgress = skF.getMin();
                }
                double freq = FrequencyResponse.progressToLog10(LOG10_30, LOG10_20K, minProgress, skF.getMax(), getSkFProgress());
                //LogPlus.d("###freq:" + freq);
                currentSelectedBand.freq = (int) freq;
                doUpdate(getPreAmp());
                //setValue(currentSelectedBand);
                setValueByDelayed();

                tvFreq.setText(String.format(getString(R.string.peq_freq), (int) (freq / 100)));
                //etFreq.setText(String.format("%.2f", getF()));//afterTextChanged
            }
        });

        skQ.setOnSeekBarChangeListener(new SimpleOnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                if (ignoreSkQChanged) {
                    return;
                }
                int minProgress = 0;
                if (isSupportedSetMin()) {
                    minProgress = skQ.getMin();
                }
                double q = FrequencyResponse.progressToLog10(LOG10_20, LOG10_2K, minProgress, skQ.getMax(), getSkQProgress());
                currentSelectedBand.q = BigDecimal.valueOf(q).setScale(2, RoundingMode.CEILING).intValue();
                doUpdate(getPreAmp());
                //setValue(currentSelectedBand);
                setValueByDelayed();

                tvQ.setText(String.format(getString(R.string.peq_q), currentSelectedBand.getQ()));
                //etQ.setText(String.format("%.2f", currentSelectedBand.q));//afterTextChanged
                //LogPlus.d("###q:" + q + " ,tvQ:" + tvQ.getText());
            }
        });

        skGain.setOnSeekBarChangeListener(new SimpleOnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                if (ignoreSkGainChanged) {
                    return;
                }
                currentSelectedBand.gain = getSkGainProgress();
                doUpdate(getPreAmp());
                //setValue(currentSelectedBand);
                setValueByDelayed();

                tvGain.setText(String.format(getString(R.string.peq_gain), currentSelectedBand.getGain()));
                //etGain.setText(String.format("%.2f", currentSelectedBand.gain));//afterTextChanged
            }
        });

        skPreAmp.setOnSeekBarChangeListener(new SimpleOnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                if (ignoreSkPreAmpChanged) {
                    return;
                }
                double preAmp = getPreAmp();
                doUpdate(preAmp);
                //setValuesByDelayed();
                setPreAmpByDelayed();

                tvPreAmp.setText(String.format(getString(R.string.peq_pre_amp), getPreAmp()));
                //etPreAmp.setText(String.format("%.2f", preAmp));//afterTextChanged
            }
        });

        filterSpinner = findViewById(R.id.sp_filter);
        final List<FilterType> filters = new ArrayList<>();
        filters.add(FilterType.LOW_SHELF);
        filters.add(FilterType.PEAKING);
        filters.add(FilterType.HIGH_SHELF);
        int itemLayoutResId = R.layout.peq_spinner_item;
        if (BuildConfig.isNewTheme()) {
            itemLayoutResId = R.layout.peq_spinner_item_newtheme;
        }
        ArrayAdapter<FilterType> filtersAdapter = new ArrayAdapter<>(this, itemLayoutResId, filters);
        filtersAdapter.setDropDownViewResource(R.layout.peq_spinner_item);
        filterSpinner.setAdapter(filtersAdapter);

        findViewById(R.id.tv_filter_sp).setOnClickListener(v -> filterSpinner.performClick());
        findViewById(R.id.tv_filter_type_icon).setOnClickListener(v -> filterSpinner.performClick());
        filterSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                if (ignoreFilterTypeChanged) {
                    return;
                }
                if (currentSelectedBand == null) {
                    LogPlus.d("currentSelectedBand is null");
                    return;
                }
                currentSelectedBand.filterType = getSelectedFilterType().getValue();
                doUpdate(getPreAmp());
                if (mPresenter != null) {
                    mPresenter.setPeqValue(currentSelectedBand, getPreAmp());
                    mPresenter.changeToNone();
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });

        findViewById(R.id.tv_enable).setOnClickListener(v -> bandSwitchButton.setChecked(!bandSwitchButton.isChecked()));

        GroupLinearLayout llFreq = findViewById(R.id.ll_freq);
        GroupLinearLayout llQ = findViewById(R.id.ll_q);
        GroupLinearLayout llGain = findViewById(R.id.ll_gain);
        GroupLinearLayout llPreAmp = findViewById(R.id.ll_pre_amp);
        GroupLinearLayout llFilterType = findViewById(R.id.ll_filter_type);
        GroupLinearLayout llOn = findViewById(R.id.ll_on);
        GroupLinearLayout llAll = findViewById(R.id.ll_all);
        for (GroupLinearLayout bg : new GroupLinearLayout[]{llFreq, llQ, llGain, llPreAmp, llFilterType, llOn, llAll}) {
            //Drawable drawable = bg.getBackground();
            //drawable.setColorFilter(null);
            //bg.setBgColor(getBgColor());
            bg.setLineColor(getLineColor());
        }

        //band0 - band9
        initBands();

        //findViewById(R.id.ll_all).setBackgroundColor(getSelectColor());
        if (!BuildConfig.isNewTheme()) {
            Drawable bk = llAll.getBackground();
            //bk.setColorFilter(null);
            if (bk instanceof ColorDrawable) {
                //((ColorDrawable) bk).setColor(getSelectColor());//
                ColorDrawable colorDrawable = new ColorDrawable();
                colorDrawable.setColor(getSelectColor());
                llAll.setBackground(colorDrawable);
            }
            llAll.setBgColor(getSelectColor());
        }

        SoundEffectPrefabsActivity.IDataTypeHandler dataTypeHandler = new SoundEffectPrefabsActivity.IDataTypeHandler() {
            @Override
            public List<SoundEffectConfig> loadCustoms() {
                ////todo 2023.6.5 迁移旧版本的sharedPreference数据
                try {
                    final String migratedPeqKey = "migratedPeqKey";
                    boolean isMigrated = ShareprefenceTool.getInstance().getBooleanShareprefence(migratedPeqKey, getApplicationContext(), false);
                    if (!isMigrated) {
                        List<PeqDataManager.PeqDataItemInfo> localDataItems = PeqDataManager.getInstance().loadPeqDataListFromLocal();
                        if (localDataItems != null) {
                            /////////////////todo 老版本第一条数据为暂存数据"无"/////////////////
                            PeqDataManager.PeqData nonePeqData = PeqDataManager.getInstance().getPeqData(TEMP_PEQ_DATA_KEY);
                            String nonePeqDataJson = PluginDataManager.getInstance().toJson(nonePeqData);
                            PeqDataManager.getInstance().savePeqData(localDataItems.get(0).name, nonePeqDataJson);
                            /////////////////todo 老版本第一条数据为暂存数据"无"/////////////////

                            for (PeqDataManager.PeqDataItemInfo peqDataItemInfo : localDataItems) {
                                if (TextUtils.isEmpty(peqDataItemInfo.name)) {
                                    if (BuildConfig.DEBUG) LogPlus.d("###name is empty skip!###");
                                    continue;
                                }

                                PluginDataManager.PeqData peqData = null;
                                try {
                                    PeqDataManager.PeqData oldPeqData = PeqDataManager.getInstance().getPeqData(peqDataItemInfo.name);
                                    if (oldPeqData != null) {
                                        peqData = new PluginDataManager.PeqData();
                                        peqData.name = oldPeqData.name;
                                        peqData.device = "";
                                        peqData.description = "";
                                        peqData.pre_amp = oldPeqData.pre_amp;
                                        peqData.bands = new ArrayList<>();
                                        for (PeqDataManager.BandItem bandItem : oldPeqData.bands) {
                                            peqData.bands.add(new PluginDataManager.BandItem().setFilter(bandItem.filter).setQ(bandItem.q).setOn(bandItem.on).setFreq(bandItem.freq).setGain(bandItem.gain));
                                        }
                                    }
                                } catch (Exception e) {
                                    e.printStackTrace();
                                    continue;
                                }
                                if (peqData == null) {
                                    continue;
                                }

                                //插入一条新的数据
                                PluginDataManager.PluginDataItem peqItem = new PluginDataManager.PluginDataItem();
                                peqItem.ischecked = true;
                                peqItem.name = peqDataItemInfo.name;
                                PluginDataManager.PluginData pluginData = new PluginDataManager.PluginData(peqItem.getId(), peqItem.getName(), peqData);
                                peqItem.setPluginData(pluginData);
                                PluginDataManager.getInstance().addDataItem(PluginDataManager.KEY_PEQ, peqItem);

                                PluginDataManager.getInstance().savePluginData(PluginDataManager.KEY_PEQ, pluginData);
                            }

                            //清除旧版本数据
                            //PeqDataManager.getInstance().deletePeqDatas();
                            ShareprefenceTool.getInstance().setBooleanSharedPreference(migratedPeqKey, true, getApplicationContext());
                        }

                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                ////todo 2023.6.5 迁移旧版本的sharedPreference数据

                List<PluginDataManager.PluginDataItem> peqDataItemInfos = PluginDataManager.getInstance().getDataItemsFromLocal(PluginDataManager.KEY_PEQ);
                List<SoundEffectConfig> configs = new ArrayList<>(peqDataItemInfos.size() + 1);
                configs.add(new SoundEffectConfig(PluginDataManager.NONE_ID, getString(R.string.peq_mseb_none), false));
                for (PluginDataManager.PluginDataItem peqDataItemInfo : peqDataItemInfos) {
                    if (TextUtils.isEmpty(peqDataItemInfo.name)) {
                        if (BuildConfig.DEBUG) LogPlus.d("###name is empty skip!###");
                        continue;
                    }
                    SoundEffectConfig config = new SoundEffectConfig(peqDataItemInfo.getId(), peqDataItemInfo.getName(), false);
                    config.setServerDataId(peqDataItemInfo.getServerDataId());
                    configs.add(config);
                }

                return configs;
            }

            @Override
            public List<SoundEffectConfig> loadSystems() throws Exception {
                List<SoundEffectConfig> configs = new ArrayList<>();
                if (mPresenter instanceof PeqActivityPresenter) {
                    List<PeqActivityPresenter.PeqInfo> peqInfos = ((PeqActivityPresenter) mPresenter).getSystemPrefabs();
                    for (PeqActivityPresenter.PeqInfo peqInfo : peqInfos) {
                        configs.add(new SoundEffectConfig(peqInfo.getName(), peqInfo.getName(), true, peqInfo.getUrl()));
                    }
                }
                return configs;
            }

            @Override
            public List<SoundEffectConfig> loadCustomsOnServer() {
                List<SoundEffectConfig> configs = null;
                if (mPresenter instanceof PeqActivityPresenter) {
                    try {
                        configs = ((PeqActivityPresenter) mPresenter).getConfigsOnServer();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                return configs;
            }

            @Override
            public List<SoundEffectConfig> loadCachedConfigsOnServer() {
                List<SoundEffectConfig> configs = null;
                if (mPresenter instanceof PeqActivityPresenter) {
                    try {
                        configs = ((PeqActivityPresenter) mPresenter).getCachedConfigs();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                return configs;
            }

            @Override
            public List<SoundEffectConfig> loadCachedSystems() {
                List<SoundEffectConfig> soundEffectConfigs = null;
                try {
                    soundEffectConfigs = ((PeqActivityPresenter) mPresenter).getCachedSystems();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return soundEffectConfigs;
            }
        };

        View llToPrefabs = findViewById(R.id.llToPrefabs);
        if (llToPrefabs != null) {
            llToPrefabs.setOnClickListener(v -> SoundEffectPrefabsActivity.startForResult(PEQActivity.this, SoundEffectPrefabsActivity.DATA_TYPE_PEQ, dataTypeHandler, SoundEffectManager.getInstance().getSelectedPEQSoundEffectConfig(), REQUEST_CODE_CHOOSE_SOUND_EFFECT_CONFIG));
        }
        View tvToSave = findViewById(R.id.tvSave);
        if (tvToSave != null) {
            tvToSave.setOnClickListener(v -> {
                SoundEffectPrefabsDialog dialog = new SoundEffectPrefabsDialog(PEQActivity.this);
                //todo 需要合并服务器端的数据
                SoundEffectConfig selectedSoundEffectConfig = SoundEffectManager.getInstance().getSelectedPEQSoundEffectConfig();

                List<SoundEffectConfig> localSoundEffectConfigs = new ArrayList<>();/*dataTypeHandler.loadCustoms();*/
                List<PluginDataManager.PluginDataItem> peqDataItemInfos = PluginDataManager.getInstance().getDataItemsFromLocal(PluginDataManager.KEY_PEQ);
                for (PluginDataManager.PluginDataItem peqDataItemInfo : peqDataItemInfos) {
                    if (TextUtils.isEmpty(peqDataItemInfo.name)) {
                        if (BuildConfig.DEBUG) LogPlus.d("###name is empty skip!###");
                        continue;
                    }
                    SoundEffectConfig config = new SoundEffectConfig(peqDataItemInfo.getId(), peqDataItemInfo.getName(), false);
                    config.setServerDataId(peqDataItemInfo.getServerDataId());
                    localSoundEffectConfigs.add(config);
                }

                //当前本地已保存到服务器的配置项
                Map<String, SoundEffectConfig> localSavedToServerConfigsMap = new HashMap<>();
                for (SoundEffectConfig soundEffectConfig : localSoundEffectConfigs) {
                    if (soundEffectConfig.getServerDataId() != null) {
                        localSavedToServerConfigsMap.put(soundEffectConfig.getServerDataId(), soundEffectConfig);
                    }

                    soundEffectConfig.setChecked(soundEffectConfig.equals(selectedSoundEffectConfig));
                }

                if (false) {
                    //已缓存的服务器端配置数据 与本地已有的数据进行合并, 如果有本地未记录的数据则添加
                    List<SoundEffectConfig> cachedConfigs = dataTypeHandler.loadCachedConfigsOnServer();
                    if (cachedConfigs != null) {
                        for (SoundEffectConfig soundEffectConfig : cachedConfigs) {
                            //如果有本地未记录的数据则添加
                            if (!localSavedToServerConfigsMap.containsKey(soundEffectConfig.getId()) && !localSoundEffectConfigs.contains(soundEffectConfig)) {
                                soundEffectConfig.setServerDataId(soundEffectConfig.getId());
                                localSoundEffectConfigs.add(soundEffectConfig);
                            }
                        }
                    }

                    //从服务器拉已保存的数据 与本地已有的数据进行合并, 如果有本地未记录的数据则添加
                    boolean isNetworkAvailable = NetWorkUtils.isConnected(getApplicationContext());
                    if (isNetworkAvailable) {
                        List<SoundEffectConfig> customConfigsOnServer = dataTypeHandler.loadCustomsOnServer();
                        if (customConfigsOnServer != null) {
                            for (SoundEffectConfig soundEffectConfig : customConfigsOnServer) {
                                //如果有本地未记录的数据则添加
                                if (!localSavedToServerConfigsMap.containsKey(soundEffectConfig.getId()) && !localSoundEffectConfigs.contains(soundEffectConfig)) {
                                    soundEffectConfig.setServerDataId(soundEffectConfig.getId());
                                    localSoundEffectConfigs.add(soundEffectConfig);
                                }
                            }
                        }
                    }
                }

                for (SoundEffectConfig config : localSoundEffectConfigs) {
                    config.setChecked(config.equals(selectedSoundEffectConfig));
                }
                dialog.setData(localSoundEffectConfigs);
                dialog.setOnSaveListener((pos, item) -> {
                    if (mPresenter == null) {
                        return;
                    }
                    if (-1 == pos) { //新增预设
                        //todo 弹出输入name弹框
                        mPresenter.showAddDialog();
                        dialog.dismiss();
                        return;
                    }
                    //todo 替换本地列表中pos位置的数据 todo 同时更新本地对应的服务器端的数据
                    mPresenter.showEditDialog(item);
                    dialog.dismiss();
                });
                dialog.show(getString(R.string.peq_title_save_to));
            });
        }

        View tvShare = findViewById(R.id.tvShare);
        if (tvShare != null) {
            //todo 暂时隐藏分享
            tvShare.setVisibility(View.VISIBLE);
            tvShare.setOnClickListener(v -> {
                //todo 分享当前配置
                if (mPresenter instanceof PeqActivityPresenter) {
                    SoundEffectConfig soundEffectConfig = SoundEffectManager.getInstance().getSelectedPEQSoundEffectConfig();
                    if (soundEffectConfig == null || PluginDataManager.NONE_ID.equals(soundEffectConfig.getId())) {
                        ToastTool.showToast(getApplicationContext(), getString(R.string.peq_pls_save));
                        ((PeqActivityPresenter) mPresenter).showPluginEditFormDialog("peq", null, null, dataItem -> {
                            SoundEffectConfig _soundEffectConfig = new SoundEffectConfig(dataItem.getId(), dataItem.getName(), false);
                            byte[] peqData = new byte[0];
                            try {
                                peqData = QrManager.getInstance().getEncoder(Constant.QR_SCHEMA_V1_PEQ).toBytes(((PeqActivityPresenter) mPresenter).getPeqData(_soundEffectConfig));
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                            QrcodeActivity.start(this, Constant.QR_SCHEMA_V1_PEQ, peqData, R.mipmap.appicon2_foreground, _soundEffectConfig.getName(), "PEQ");
                        });
                        return;
                    }
                    new Thread(() -> {
                        byte[] peqData = new byte[0];
                        try {
                            peqData = QrManager.getInstance().getEncoder(Constant.QR_SCHEMA_V1_PEQ).toBytes(((PeqActivityPresenter) mPresenter).getPeqData(soundEffectConfig));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        QrcodeActivity.start(this, Constant.QR_SCHEMA_V1_PEQ, peqData, R.mipmap.appicon2_foreground, soundEffectConfig.getName(), "PEQ");
                    }).start();
                }
            });
        }

        View tvToImport = findViewById(R.id.tvToImport);
        if (tvToImport != null) {
            tvToImport.setOnClickListener(v -> {
                if (mPresenter != null) {
                    mPresenter.showImport();
                }
            });
        }

        View vReset = findViewById(R.id.tvReset);
        if (vReset != null) {
            vReset.setOnClickListener(v -> {
                if (mPresenter instanceof PeqActivityPresenter) {
                    ((PeqActivityPresenter) mPresenter).showResetMixerSettings(PEQActivity.this, () -> {
                        mPresenter.changeToNone();
                        PluginDataManager.PeqData peqData = PluginDataManager.getInstance().newNonePeqData();
                        updateBands(peqData);
                    });
                }
            });
        }

        View vGuide = findViewById(R.id.tvGuide);
        if (vGuide != null) {
            vGuide.setOnClickListener(v -> showGuidDialog(true));
        }

        final String IS_NEVER_SHOW = "peq_IS_NEVER_SHOW";
        boolean isNeverShow = ShareprefenceTool.getInstance().getBooleanShareprefence(IS_NEVER_SHOW, getApplicationContext(), false);
        if (!isNeverShow) showGuidDialog(false);

        //是否处于Mqa播放中
        boolean isMmqPlaying = MmqStateTools.getInstance().currentMusicIsMMq();
        // 初始化配置中的状态
        boolean isOpened = ShareprefenceTool.getInstance().getBooleanShareprefence(PEQ_ISOPEN, this.getApplicationContext(), false);
        globalSwitchButton.setChecked(isOpened/*&& !isMmqPlaying*/);
        enableViews();
        mPresenter.setPEQEnable(isOpened, (float) getPreAmp(), isOpened);
        this.mPresenter.init();
        handleIntent();
    }

    private void initSeekbars() {
        boolean isSupportedSetMin = isSupportedSetMin();
        if (isSupportedSetMin) {
            skF.setMax(20000 * 100);//30 - 20k
            skF.setMin(getSkFMinValue());

            skQ.setMax(20 * 100 * 100);//0.2 - 20
            skQ.setMin(getSkQMinValue());

            skGain.setMax(9 * 100 * 100);//-9 - +9
            skGain.setMin(getSkGainMinValue());

            skPreAmp.setMax(2 * 100 * 100);//-9 - +2
            skPreAmp.setMin(getSkPreampMinValue());
        } else {
            skF.setMax(20000 * 100 - getSkFOffsetValue());
            skQ.setMax(20 * 100 * 100 - getSkQOffsetValue());
            skGain.setMax(9 * 100 * 100 - getSkGainOffsetValue());
            skPreAmp.setMax(2 * 100 * 100 - getSkPreampOffsetValue());
        }
    }


    private int getSkFProgress() {
        return skF.getProgress() + getSkFOffsetValue();
    }

    private int getSkQProgress() {
        return skQ.getProgress() + getSkQOffsetValue();
    }

    private int getSkGainProgress() {
        return skGain.getProgress() + getSkGainOffsetValue();
    }

    private int getSkPreampProgress() {
        return skPreAmp.getProgress() + getSkPreampOffsetValue();
    }

    private int getSkPreampOffsetValue() {
        boolean isSupportedSetMin = isSupportedSetMin();
        return isSupportedSetMin ? 0 : getSkPreampMinValue();
    }

    private int getSkGainOffsetValue() {
        boolean isSupportedSetMin = isSupportedSetMin();
        return isSupportedSetMin ? 0 : getSkGainMinValue();
    }

    private int getSkQOffsetValue() {
        boolean isSupportedSetMin = isSupportedSetMin();
        return isSupportedSetMin ? 0 : getSkQMinValue();
    }

    private int getSkFOffsetValue() {
        boolean isSupportedSetMin = isSupportedSetMin();
        return isSupportedSetMin ? 0 : getSkFMinValue();
    }

    private int getSkFMinValue() {
        return 30 * 100;
    }

    private int getSkQMinValue() {
        return (int) (0.2 * 100 * 100);
    }

    private int getSkGainMinValue() {
        return -9 * 100 * 100;
    }

    private int getSkPreampMinValue() {
        return -9 * 100 * 100;
    }

    private boolean isSupportedSetMin() {
        return Build.VERSION.SDK_INT > Build.VERSION_CODES.O_MR1 /*&&*/
                /*R5 seekbar.setMin() invalid*/
                /*!com.hiby.music.smartplayer.utils.Util.checkDeviceIsModelR5()*/;
    }

    public static final String PEQ_ISOPEN = "PEQ_ISOPEN";

    private final PorterDuffColorFilter skColorFilter = new PorterDuffColorFilter(Color.argb(100, 100, 100, 100), PorterDuff.Mode.SRC_ATOP);

    private void enableViews() {
        ////////////////有调整则开启 2023.6.21 操作调音选项的时候，改为调音系统自动直接开启，不用弹出关闭字样。mseb peq eq 相同//////////////////
        if (false) {
            for (TextView v : new TextView[]{tvFreq, tvQ, tvGain/*, tvPreAmp*/}) {
                v.setEnabled(bandSwitchButton.isChecked() && globalSwitchButton.isChecked());
            }
            for (SeekBar sk : new SeekBar[]{skF, skQ, skGain/*, skPreAmp*/}) {
                enableSeekbar(sk, bandSwitchButton.isChecked() && globalSwitchButton.isChecked());
            }
            filterSpinner.setEnabled(bandSwitchButton.isChecked() && globalSwitchButton.isChecked());
            findViewById(R.id.tv_filter_sp).setEnabled(bandSwitchButton.isChecked() && globalSwitchButton.isChecked());
            findViewById(R.id.tv_filter_type_icon).setEnabled(bandSwitchButton.isChecked() && globalSwitchButton.isChecked());

            bandSwitchButton.setEnabled(globalSwitchButton.isChecked());
            findViewById(R.id.tv_enable).setEnabled(globalSwitchButton.isChecked());
            findViewById(R.id.tv_pre_amp).setEnabled(globalSwitchButton.isChecked());
            enableSeekbar(skPreAmp, globalSwitchButton.isChecked());
        }
        ////////////////有调整则开启 2023.6.21 操作调音选项的时候，改为调音系统自动直接开启，不用弹出关闭字样。mseb peq eq 相同//////////////////
    }

    private void enableSeekbar(SeekBar sk, boolean enabled) {
        sk.setEnabled(enabled);
        sk.getThumb().setColorFilter(!enabled ? skColorFilter : null);
        Drawable drawable = sk.getProgressDrawable();
        if (drawable instanceof LayerDrawable) {
            LayerDrawable layerDrawable = (LayerDrawable) drawable;
            Drawable dra = layerDrawable.getDrawable(2);
            dra.setColorFilter(!enabled ? 0xeeaaaaaa : getApplicationContext().getResources().getColor(SkinManager.get().getIconColorSupportCustom()), PorterDuff.Mode.SRC_ATOP);
        }
    }

    private int getFilterPos(int filterType) {
        return filterType;
    }

    private PeqParamDialog peqParamDialog;

    private void showParamValueDialog(String title, String value, PeqParamDialog.ConfirmListener confirmListener) {
        if (peqParamDialog != null) {
            peqParamDialog.getDialog().dismiss();
            peqParamDialog = null;
        }
        peqParamDialog = new PeqParamDialog(this, title);
        peqParamDialog.showDialog(value, confirmListener);
    }

    private void refreshDataToUI() {
        int skFMin = 0;
        if (isSupportedSetMin()) {
            skFMin = skF.getMin();
        }
        skF.setProgress(FrequencyResponse.log10ToProgress(LOG10_30, LOG10_20K, skFMin, skF.getMax(), currentSelectedBand.freq) - getSkFOffsetValue());

        int skQMin = 0;
        if (isSupportedSetMin()) {
            skQMin = skQ.getMin();
        }
        skQ.setProgress(FrequencyResponse.log10ToProgress(LOG10_20, LOG10_2K, skQMin, skQ.getMax(), currentSelectedBand.q) - getSkQOffsetValue());

        skGain.setProgress(currentSelectedBand.gain - getSkGainOffsetValue());
        //skPreAmp.setProgress(0);

        tvFreq.setText(String.format(getString(R.string.peq_freq), currentSelectedBand.freq / 100));
        tvQ.setText(String.format(getString(R.string.peq_q), currentSelectedBand.getQ()));
        tvGain.setText(String.format(getString(R.string.peq_gain), currentSelectedBand.getGain()));
        tvPreAmp.setText(String.format(getString(R.string.peq_pre_amp), getPreAmp()));
    }

    public double getPreAmp() {
        return getSkPreampProgress() / 100f / 100;
    }

    @Override
    public void showQrcode(Bitmap qrBitmap) {
        //QrTemplate.getInstance().showQrcode(findViewById(R.id.rl_qr), qrBitmap);
    }

    public int preAmpToProgress(double preAmp) {
        return (int) (preAmp * 100 * 100);
    }

    private IndTextView[] indTextViews;

    private void initBands() {
        bands = new ArrayList<>();
        final int[] freqs = {31, 62, 125, 250, 500, 1000, 2000, 4000, 8000, 16000};
        final int bandsCount = 10;
        for (int i = 0; i < bandsCount; ++i) {
            final String title = "Band" + i;
            Band band = new Band(i, title);
            band.freq = freqs[i] * 100;
            bands.add(band);
        }

        LinearLayout itemLinearLayout = findViewById(R.id.hs_linerLayout);
        indTextViews = new IndTextView[bands.size()];
        int i = 0;
        for (Band band : bands) {
            View bandItemView = LayoutInflater.from(this).inflate(R.layout.peq_peq_band_item, null);
            IndTextView tvTitle = bandItemView.findViewById(R.id.tv_title);
            tvTitle.setText(band.title);
            tvTitle.setIndEnable(band.on);
            tvTitle.setSelectColor(getSelectColor());
            if (BuildConfig.isNewTheme()) tvTitle.setBackgroundResource(R.drawable.peq_selector_item);
            indTextViews[i++] = tvTitle;
            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT);
            lp.leftMargin = 4;
            lp.rightMargin = 4;
            itemLinearLayout.addView(bandItemView, lp);
            bandItemView.setOnClickListener(v -> onBandItemClick(band, tvTitle, bandItemView));
        }

        //默认选中第一个band
        itemLinearLayout.getChildAt(0).performClick();
    }

    private int getSelectColor() {
        if (SkinManager.get().getThemeMode() == SkinManager.BLACK_MODE) {
            return 0x55666666;
        }
        if (SkinManager.get().getThemeMode() == SkinManager.GREEN_MODE) {
            return 0xEE114f5C;
        }
        CenterLockHorizontalScrollviewWithTabBg centerLockHorizontalScrollviewWithTabBg = findViewById(R.id.scrollView);
        Drawable drawable = centerLockHorizontalScrollviewWithTabBg.getBackground();
        if (drawable instanceof ColorDrawable) {
            int color = ((ColorDrawable) drawable).getColor();
            int red = (color & 0xff0000) >> 16;
            int green = (color & 0x00ff00) >> 8;
            int blue = (color & 0x0000ff);
            red *= .5f;
            /*green *= .5f;
            blue *= .5f;*/
            int alpha = 200;
            //return (alpha << 24) | (red << 16) | (green << 8) | blue;
            return getResources().getColor(R.color.peq_skin_background);
        }
        return 0xEE666666;
    }

    private long lastOnBandItemClickAt;

    private void onBandItemClick(Band band, IndTextView tvTitle, View bandItemView) {
        if (currentSelectedBand == band) {
            //////////////double tap to on////////////////////
            if (SystemClock.uptimeMillis() - lastOnBandItemClickAt < 500) {
                currentSelectedBand.on = !currentSelectedBand.on;
                bandSwitchButton.setChecked(currentSelectedBand.on);
                enableViews();
                tvTitle.setIndEnable(currentSelectedBand.on);

                lastOnBandItemClickAt = 0;

                if (mPresenter != null) {
                    mPresenter.setPeqValues(bands, getPreAmp());
                    mPresenter.setPEQEnable(globalSwitchButton.isChecked(), (float) getPreAmp(), globalSwitchButton.isChecked());
                }
                return;
            }
            lastOnBandItemClickAt = SystemClock.uptimeMillis();
            //////////////double tap to on////////////////////
            return;
        }
        //////////////double tap to on////////////////////
        lastOnBandItemClickAt = SystemClock.uptimeMillis();
        //////////////double tap to on////////////////////

        //todo 读取当前频响并设置到
        //float[] values = getFreqResponse();

        if (currentSelectedBand != null) {
            currentSelectedBand.isSelected = false;
        }
        if (currentSelectedBandView != null) {
            SkinManager.get().setTextViewColor(currentSelectedBandView, R.color.peq_skin_secondary_text);
            if (BuildConfig.isNewTheme()) {
                currentSelectedBandView.setTextColor(getResources().getColor(R.color.peq_white));
            }
            currentSelectedBandView.setTabStyle(IndTextView.TabBgStyle.NONE);
            currentSelectedBandView.setSelected(false);
        }
        band.isSelected = true;
        currentSelectedBand = band;
        currentSelectedBandView = tvTitle;
        tvTitle.setIndEnable(band.on);
        SkinManager.get().setTextViewColor(tvTitle, R.color.peq_skin_primary_text);
        if (BuildConfig.isNewTheme()) {
            tvTitle.setTextColor(getResources().getColor(R.color.peq_white));
        }
        CenterLockHorizontalScrollviewWithTabBg centerLockHorizontalScrollviewWithTabBg = findViewById(R.id.scrollView);
        centerLockHorizontalScrollviewWithTabBg.setCenter(bandItemView);
        //忽略接下来的view set 事件回调, 与由用户修改操作区分
        ignoreAllChangedWithoutListener();

        bandSwitchButton.setChecked(currentSelectedBand.on);
        enableViews();
        indTextViews[currentSelectedBand.index].setIndEnable(bandSwitchButton.isChecked());

        filterSpinner.setSelection(getFilterPos(currentSelectedBand.filterType));//存在延时调用 onItemSelected 的问题

        refreshDataToUI();

        SmartPlayerApplication.getMainHandler().postDelayed(this::invalidAllIgnored, 300);//filterSpinner.setSelection 存在延时调用 onItemSelected 的问题
        doUpdate(getPreAmp());

        centerLockHorizontalScrollviewWithTabBg.setSelectedItemView(bandItemView);

        tvTitle.setTabStyle(getTabBgStyle(currentSelectedBand));
        tvTitle.setSelected(true);
    }

    @Override
    protected void onResume() {
        super.onResume();

        //是否处于Mqa播放中
        boolean isMmqPlaying = MmqStateTools.getInstance().currentMusicIsMMq();
        // 初始化配置中的状态
        boolean isOpened = ShareprefenceTool.getInstance().getBooleanShareprefence(PEQ_ISOPEN, this.getApplicationContext(), false);
        if (BuildConfig.DEBUG) LogPlus.d("###isOpened:" + isOpened);
        globalSwitchButton.setChecked(isOpened && !isMmqPlaying);

        QrManager.getInstance().setOnDecodeCallback(new QrManager.OnDecodeCallback() {
            @Override
            public void onDecoded(String imagePath, String qrContent) {
                //todo 解析二维码内容并导入数据
                if (mPresenter != null) mPresenter.onQrcodeDecoded(qrContent);
            }

            @Override
            public void onDecodeFailed(String imagePath, Exception e) {
                ToastTool.showToast(getApplicationContext(), e != null ? e.getLocalizedMessage() : getString(R.string.peq_qrcode_failed));
            }
        });

        SoundEffectConfig soundEffectConfig = SoundEffectManager.getInstance().getSelectedPEQSoundEffectConfig();
        if (soundEffectConfig != null) {
            PluginDataManager.PeqData peqData = PluginDataManager.getInstance().getPluginDataValue(PluginDataManager.KEY_PEQ, soundEffectConfig.getId(), new TypeToken<PluginDataManager.PeqData>() {
            });
            updateCurrentStyleName(soundEffectConfig.getName());
            if (peqData != null) updateBands(peqData);
        }
    }

    @Override
    protected void onPause() {
        if (mPresenter != null) mPresenter.onPause();
        super.onPause();
    }

    @Override
    protected void onStop() {
        super.onStop();
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);

    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
    }

    @Override
    protected void onDestroy() {
        //if (mPresenter != null) mPresenter.onDestroy();
        super.onDestroy();
    }

    /**
     * 更新折线图
     *
     * @param preAmp 前置放大
     */
    private void doUpdate(double preAmp) {
        //采样频率
        int fs = 44100;
        //滤波器
        updateLines(fs, preAmp);
    }

    /**
     * 绘制多频段叠加曲线
     *
     * @param fs
     * @param preAmp
     */
    private void updateLines(int fs, double preAmp) {
        final int n = 400;
        double startF = 20;
        double endF = 20000;
        double logStep = (Math.log10(endF) - Math.log10(startF)) / n;
        double step = Math.pow(10, logStep);

        double[] f = new double[n];
        double[] semilogf = new double[n];
        for (int i = 0; i < n; i++) {
            f[i] = startF * Math.pow(step, i); //按对数划分为n个点
            //if (BuildConfig.DEBUG) LogPlus.d("f[" + i + "]:" + f[i]);
            semilogf[i] = Math.log10(f[i]);  //半对数绘制时，对f取以10为底的对数
            //if (BuildConfig.DEBUG) LogPlus.d("semilogf[" + i + "]:" + semilogf[i]);
        }

        List<double[]> xValuesList = new ArrayList<>();
        List<double[]> yValuesList = new ArrayList<>();

        //当前已选择的频段频响
        double[] freqResponseCurrentYValues = new double[n];
        //////全部频段(band0-band9)叠加//////
        double[] freqResponseAllBandsYValues = new double[n];
        for (int bandIndex = 0, bandsLen = bands.size(); bandIndex < bandsLen; ++bandIndex) {
            Band band = bands.get(bandIndex);
            if (!band.on) continue;
            //滤波器
            FilterType filterType = convertFilterType(band.filterType);
            Coeff coeff = FilterManager.getInstance().getFilter(filterType).getValue(band.getFreq(), band.getQ(), band.getGain(), fs);
            if (!Double.isNaN(coeff.getB0()) && !Double.isNaN(coeff.getB1()) && !Double.isNaN(coeff.getB2()) && !Double.isNaN(coeff.getA0()) && !Double.isNaN(coeff.getA1()) && !Double.isNaN(coeff.getA2())) {
                double[] yValues = FrequencyResponse.getFreqzn(coeff, fs, f);
                if (bandIndex == currentSelectedBand.index) {
                    freqResponseCurrentYValues = yValues;
                }
                for (int i = 0, len = yValues.length; i < len; i++) {
                    freqResponseAllBandsYValues[i] += yValues[i];
                }
            }
        }
        //////全部频段(band0-band9)叠加//////

        xValuesList.add(semilogf);
        yValuesList.add(freqResponseAllBandsYValues);

        //////0dB, current selected band//////
        xValuesList.add(xValuesList.get(0));
        yValuesList.add(freqResponseCurrentYValues);
        //////0dB, current selected band//////

        lineView.updateLines(new String[yValuesList.size()], xValuesList, yValuesList, true, preAmp); //半对数绘制
    }

    private FilterType convertFilterType(int filterType) {
        return new FilterType[]{FilterType.LOW_SHELF, FilterType.PEAKING, FilterType.HIGH_SHELF}[filterType];
    }

    private FilterType getSelectedFilterType() {
        Spinner spFilter = findViewById(R.id.sp_filter);
        if (spFilter != null) {
            return (FilterType) spFilter.getSelectedItem();
        }
        return FilterType.PEAKING;
    }

    @Override
    public void updateBands(PluginDataManager.PeqData peqData) {
        if (peqData == null || peqData.bands == null) return;
        if (BuildConfig.DEBUG) {
            if (peqData.bands.size() != this.bands.size()) {
                LogPlus.d("peq 配置文件bands 数量<" + this.bands.size());
            }
        }

        if (currentSelectedBandView != null) {
            SkinManager.get().setTextViewColor(currentSelectedBandView, R.color.peq_skin_secondary_text);
            if (BuildConfig.isNewTheme()) {
                currentSelectedBandView.setTextColor(getResources().getColor(R.color.peq_white));
            }
            currentSelectedBandView.setTabStyle(IndTextView.TabBgStyle.NONE);
        }

        int len = Math.min(peqData.bands.size(), this.bands.size());
        for (int i = 0; i < len; ++i) {
            Band band = this.bands.get(i);
            PluginDataManager.BandItem serverBand = peqData.bands.get(i);
            band.setFreq(serverBand.freq);
            band.setQ(serverBand.q);
            band.setGain(serverBand.gain);
            band.setOn(serverBand.on);
            band.setFilterType(serverBand.filter);
            indTextViews[i].setIndEnable(band.on);
            SkinManager.get().setTextViewColor(indTextViews[i], R.color.peq_skin_secondary_text);
            if (BuildConfig.isNewTheme()) {
                indTextViews[i].setTextColor(getResources().getColor(R.color.peq_white));
            }
        }
        currentSelectedBand = this.bands.get(0);
        currentSelectedBand.isSelected = true;
        currentSelectedBandView = indTextViews[0];

        currentSelectedBandView.setTabStyle(getTabBgStyle(currentSelectedBand));

        SkinManager.get().setTextViewColor(currentSelectedBandView, R.color.peq_skin_primary_text);
        if (BuildConfig.isNewTheme()) {
            currentSelectedBandView.setTextColor(getResources().getColor(R.color.peq_white));
        }
        //部分view 设置值会回调 OnChangedListener, 如此设置忽略一次由程序调用(与用户操作区分开)的回调处理
        ignoreAllChangedWithoutListener();

        filterSpinner.setSelection(getFilterPos(currentSelectedBand.filterType));
        bandSwitchButton.setChecked(currentSelectedBand.on);
        enableViews();
        //currentSelectedBandView.setSelected(true);
        SkinManager.get().setTextViewColor(indTextViews[0], R.color.peq_skin_primary_text);
        if (BuildConfig.isNewTheme()) {
            indTextViews[0].setTextColor(getResources().getColor(R.color.peq_white));
        }

        skPreAmp.setProgress(preAmpToProgress(peqData.pre_amp) - getSkPreampOffsetValue());

        refreshDataToUI();

        //invalidAllIgnored();
        SmartPlayerApplication.getMainHandler().postDelayed(this::invalidAllIgnored, 1000);//filterSpinner.setSelection 存在延时调用 onItemSelected 的问题

        doUpdate(getPreAmp());

        if (mPresenter != null) {
            mPresenter.setPeqValues(bands, getPreAmp());
            mPresenter.setPEQEnable(globalSwitchButton.isChecked(), (float) getPreAmp(), globalSwitchButton.isChecked());
        }
    }

    private IndTextView.TabBgStyle getTabBgStyle(Band currentSelectedBand) {
        if (BuildConfig.isNewTheme()) {
            return IndTextView.TabBgStyle.NEW_THEME;
        }
        IndTextView.TabBgStyle tabBgStyle = IndTextView.TabBgStyle.MIDDLE;
        if (currentSelectedBand.index == 0) {
            tabBgStyle = IndTextView.TabBgStyle.LEFT;
        } else if (currentSelectedBand.index == bands.size() - 1) {
            tabBgStyle = IndTextView.TabBgStyle.RIGHT;
        }
        return tabBgStyle;
    }

    @Override
    public void updateCurrentStyleName(String name) {
        runOnUiThread(() -> {
            ((TextView) findViewById(R.id.preset_value)).setText(name);
            ((TextView) findViewById(R.id.tvToPrefabs)).setText(name);
            ((TextView) findViewById(R.id.tvToPrefabs)).setSelected(true);//marqueue

            if (BuildConfig.isNewTheme()) {
                TextView tvToPrefabs = findViewById(R.id.tvToPrefabs);
                insertImageSpan(tvToPrefabs, getDrawable(R.drawable.peq_ic_preset), name);

                TextView tvSave = findViewById(R.id.tvSave);
                insertImageSpan(tvSave, getDrawable(R.drawable.peq_ic_save), getString(R.string.peq_save));

                TextView tvImport = findViewById(R.id.tvToImport);
                insertImageSpan(tvImport, getDrawable(R.drawable.peq_ic_import), getString(R.string.peq_import2));
            }
        });
    }

    private void insertImageSpan(TextView tv, Drawable d, String text) {
        d.setBounds(0, 0, 38, 38);
        SpannableString ssb = new SpannableString("  " + text);
        ssb.setSpan(new VerticalAlignImageSpan(d), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        tv.setText(ssb);
    }

    @Override
    public List<Band> getBands() {
        return bands;
    }

    private float[] getFreqResponse() {
        float[] values = null;//(float[]) SmartAv.getInstance().getObjectAttr("peq_response");
        //values.length 2160
        //if (BuildConfig.DEBUG) LogPlus.d("values:" + Arrays.toString(values));
        return values;
    }

    public static void start(Context context, int frequency) {
        Intent it = new Intent(context, PEQActivity.class);
        it.putExtra("freq", frequency);
        context.startActivity(it);
    }

    /**
     * 设定当前选择的band
     */
    private final Runnable setValueRunnable = () -> {
        if (mPresenter != null) {
            mPresenter.setPeqValue(currentSelectedBand, getPreAmp());
            mPresenter.changeToNone();
        }

        // 如果当前歌曲不支持调音则进行提示
        boolean isMmqPlaying = MmqStateTools.getInstance().currentMusicIsMMq();
        if (isMmqPlaying) {
            ToastTool.showToast(this, getResources().getString(R.string.mmq_state_try_agin_next));
        }

        bandSwitchButton.setChecked(true);

        if (!globalSwitchButton.isChecked()) {
            ////////////////有调整则开启 2023.6.21 操作调音选项的时候，改为调音系统自动直接开启，不用弹出关闭字样。mseb peq eq 相同//////////////////
            globalSwitchButton.setChecked(true);
            ////////////////有调整则开启 2023.6.21 操作调音选项的时候，改为调音系统自动直接开启，不用弹出关闭字样。mseb peq eq 相同//////////////////
            mPresenter.setPEQEnable(globalSwitchButton.isChecked(), (float) getPreAmp(), globalSwitchButton.isChecked());
        }
    };

    /**
     * 设定当前选择的band
     */
    private void setValueByDelayed() {
        SmartPlayerApplication.getMainHandler().removeCallbacks(setValueRunnable);
        SmartPlayerApplication.getMainHandler().postDelayed(setValueRunnable, 50);
    }

    /**
     * 设定所有的bands
     */
    private final Runnable setValuesRunnable = () -> {
        if (mPresenter != null) {
            ////////////////有调整则开启 2023.6.21 操作调音选项的时候，改为调音系统自动直接开启，不用弹出关闭字样。mseb peq eq 相同//////////////////
            globalSwitchButton.setChecked(true);
            ////////////////有调整则开启 2023.6.21 操作调音选项的时候，改为调音系统自动直接开启，不用弹出关闭字样。mseb peq eq 相同//////////////////

            // 如果当前歌曲不支持调音则进行提示
            boolean isMmqPlaying = MmqStateTools.getInstance().currentMusicIsMMq();
            if (isMmqPlaying) {
                ToastTool.showToast(this, getResources().getString(R.string.mmq_state_try_agin_next));
            }

            mPresenter.setPeqValues(bands, getPreAmp());
            mPresenter.changeToNone();
            mPresenter.setPEQEnable(globalSwitchButton.isChecked(), (float) getPreAmp(), globalSwitchButton.isChecked());
        }
    };

    /**
     * 设定所有的bands
     */
    private void setValuesByDelayed() {
        SmartPlayerApplication.getMainHandler().removeCallbacks(setValuesRunnable);
        SmartPlayerApplication.getMainHandler().postDelayed(setValuesRunnable, 50);
    }

    /**
     * 设定PreAmp
     */
    private final Runnable setPreAmpRunnable = () -> {
        if (mPresenter != null) {
            mPresenter.setPeqPreAmp(getPreAmp());
            mPresenter.changeToNone();
            mPresenter.setPEQEnable(globalSwitchButton.isChecked(), (float) getPreAmp(), globalSwitchButton.isChecked());
        }

        // 如果当前歌曲不支持调音则进行提示
        boolean isMmqPlaying = MmqStateTools.getInstance().currentMusicIsMMq();
        if (isMmqPlaying) {
            ToastTool.showToast(this, getResources().getString(R.string.mmq_state_try_agin_next));
        }

        ////////////////有调整则开启 2023.6.21 操作调音选项的时候，改为调音系统自动直接开启，不用弹出关闭字样。mseb peq eq 相同//////////////////
        globalSwitchButton.setChecked(true);
        bandSwitchButton.setChecked(true);
        ////////////////有调整则开启 2023.6.21 操作调音选项的时候，改为调音系统自动直接开启，不用弹出关闭字样。mseb peq eq 相同//////////////////
    };

    private void setPreAmpByDelayed() {
        SmartPlayerApplication.getMainHandler().removeCallbacks(setPreAmpRunnable);
        SmartPlayerApplication.getMainHandler().postDelayed(setPreAmpRunnable, 50);
    }

    private int getThumbDrawableResId() {
        if (SkinManager.get().getThemeMode() == SkinManager.GREEN_MODE) {
            return R.mipmap.peq_ic_eq_progress_left_nor_green;
        } else if (SkinManager.get().getThemeMode() == SkinManager.CUSTOM_MODE) {
            return R.mipmap.peq_ic_eq_progress_right_nor;
        }
        return R.mipmap.peq_ic_eq_progress_left_nor;
    }

    private int getLineColor() {
        if (SkinManager.BLACK_MODE == SkinManager.get().getThemeMode()) {
            return R.color.peq_white_01;
        }
        String theme = SkinManager.getTheme(this);
        if ("green".equals(theme)) {
            return R.color.peq_white_01;
        } else if (theme.startsWith("custom")) {
            return SkinManager.get().getCustomColor();
        }
        return R.color.peq_black;
    }

    private boolean ignoreBandSwitchChanged, ignoreFilterTypeChanged, ignoreSkFChanged, ignoreSkQChanged, ignoreSkGainChanged, ignoreSkPreAmpChanged;

    /**
     * 部分view 设置值会回调 OnChangedListener, 如此设置忽略一次由程序调用(与用户操作区分开)的回调处理
     */
    private void ignoreAllChangedWithoutListener() {
        ignoreBandSwitchChanged = ignoreFilterTypeChanged = ignoreSkFChanged = ignoreSkQChanged = ignoreSkGainChanged = ignoreSkPreAmpChanged = true;
    }

    private void invalidAllIgnored() {
        ignoreBandSwitchChanged = ignoreFilterTypeChanged = ignoreSkFChanged = ignoreSkQChanged = ignoreSkGainChanged = ignoreSkPreAmpChanged = false;
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_QR_CODE) {
            if (data != null) {
                int resultType = data.getIntExtra("result_type", XQRCode.RESULT_FAILED/*failed*/);
                if (resultType == XQRCode.RESULT_SUCCESS) {
                    String resultData = data.getStringExtra("result_data");
                    if (mPresenter != null) mPresenter.onQrcodeDecoded(resultData);
                }
            }
            return;
        }
        if (requestCode == REQUEST_IMAGE) {
            if (data == null) return;
            String imagePath = ImageUtil.getImageAbsolutePath(this, data.getData());
            QrManager.getInstance().decodeQrcode(imagePath, new QrManager.OnDecodeCallback() {
                @Override
                public void onDecoded(String imagePath, String qrContent) {
                    if (mPresenter != null) mPresenter.onQrcodeDecoded(qrContent);
                }

                @Override
                public void onDecodeFailed(String imagePath, Exception e) {
                    ToastTool.showToast(getApplicationContext(), getString(R.string.peq_qrcode_failed));
                }
            });
            return;
        }
        if (requestCode == REQUEST_CODE_CHOOSE_SOUND_EFFECT_CONFIG) {
            if (BuildConfig.DEBUG) LogPlus.d("###REQUEST_CODE_CHOOSE_SOUND_EFFECT_CONFIG  data : " + data);
            if (data == null) return;
            SoundEffectConfig soundEffectConfig = (SoundEffectConfig) data.getSerializableExtra(SoundEffectPrefabsActivity.RESULT_NAME);
            if (soundEffectConfig == null) return;
            updateCurrentStyleName(soundEffectConfig.getName());

            //设置开关为当前值(上一个界面操作已设置为开)
            boolean isOpened = ShareprefenceTool.getInstance().getBooleanShareprefence(PEQ_ISOPEN, this.getApplicationContext(), false);
            if (globalSwitchButton != null) globalSwitchButton.setChecked(isOpened);//后续的操作有可能用到当前 switchButton的状态

            mPresenter.importDataToLocal(soundEffectConfig);

            SoundEffectManager.getInstance().saveSoundEffectConfigAsPEQ(soundEffectConfig);
            return;
        }
    }

    private static final int REQUEST_CODE_CHOOSE_SOUND_EFFECT_CONFIG = 2221;

    private static final String PEQ_DATA_KEY = "peqData";

    public static void start(Context context, PluginDataManager.PeqData peqData) {
        Intent it = new Intent(context, PEQActivity.class);
        it.putExtra(PEQ_DATA_KEY, peqData);
        context.startActivity(it);
    }

    private static long lastHandleIntentAt;

    private void handleIntent() {
        if (System.currentTimeMillis() - lastHandleIntentAt <= 4000) {//Let’s deal with it like this for now
            return;
        }
        lastHandleIntentAt = System.currentTimeMillis();

        Intent it = getIntent();
        if (it == null) {
            return;
        }
        //因为PeqData 中 transient 因此此反序列化过程会忽略某些字段 ,
        Object peqData = it.getSerializableExtra(PEQ_DATA_KEY);
        if (peqData != null) {
            PluginDataManager.PeqData data = (PluginDataManager.PeqData) peqData;
            this.mPresenter.importDataFromLocal(data);
        }
    }

    ////////////////////老版本临时数据//////////////////
    private static final String TEMP_PEQ_DATA_KEY = "__temp__";
    ////////////////////老版本临时数据//////////////////


    public void showGuidDialog(boolean isHideNeverShowCheckBox) {
        final CommanDialog dialog = new CommanDialog(this, R.style.peqMyDialogStyle, CommanDialog.STYLE_NOTITLE_NOBUTTON);
        dialog.setCanceledOnTouchOutside(true);
        View view = View.inflate(this, R.layout.peq_guide_dialog_item, null);
        dialog.addView(view);
        ImageView mGuid_img = view.findViewById(R.id.guid_img);
        CheckBox mGuid_checkbox = view.findViewById(R.id.guid_checkbox);
        Button mButton_ensure = view.findViewById(R.id.button_ensure);

        int langusgecode = DspUtil.getInstance().getLangusgecode(getApplicationContext());
        switch (langusgecode) {
            case 0:
                mGuid_img.setImageResource(R.mipmap.peq_guid_img_en2);
                break;
            case 1:
                mGuid_img.setImageResource(R.mipmap.peq_guid_img_cn2);
                break;
            case 2:
                mGuid_img.setImageResource(R.mipmap.peq_guid_img_hk2);
                break;
            default:
                mGuid_img.setImageResource(R.mipmap.peq_guid_img_en2);
        }

        if (isHideNeverShowCheckBox) {
            mGuid_checkbox.setVisibility(View.GONE);
        } else {
            mGuid_checkbox.setVisibility(View.VISIBLE);
        }
        dialog.setOnDismissListener(dialog1 -> {
            if (!isHideNeverShowCheckBox) {
                boolean checked = mGuid_checkbox.isChecked();
                final String IS_NEVER_SHOW = "peq_IS_NEVER_SHOW";
                ShareprefenceTool.getInstance().setBooleanSharedPreference(IS_NEVER_SHOW, checked, getApplicationContext());
            }
        });
        mButton_ensure.setOnClickListener(v -> dialog.dismiss());
        dialog.show();
    }
}
